package cc.rengu.redp.base.authentication;

import cc.rengu.redp.common.properties.RedpProperties;
import cc.rengu.redp.common.utils.EncryptUtil;
import cc.rengu.redp.common.utils.SpringContextUtil;
import cc.rengu.redp.common.utils.gmhelper.SM4Util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Date;

@Slf4j
public class UpmpJWTUtil {

    private static final long EXPIRE_TIME = SpringContextUtil.getBean(RedpProperties.class).getShiro().getJwtTimeOut() * 1000;

    /**
     * JWT 采用随机密钥和向量
     */
    private static byte[] KEY = SpringContextUtil.getBean(RedpProperties.class).getShiro().getJwtKey().getBytes();
    private static byte[] IV = new StringBuffer(SpringContextUtil.getBean(RedpProperties.class).getShiro().getJwtKey())
            .reverse().toString().getBytes();

    /**
     * 校验 token是否正确
     *
     * @param token  密钥
     * @param secret 用户的密码
     * @return 是否正确
     */
    public static boolean verify(String token, String userid, String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim("upmpuserid", userid)
                    .build();
            verifier.verify(token);
            return true;
        } catch (Exception e) {
            log.warn("token is invalid{}", e.getMessage());
            return false;
        }
    }

    /**
     * 从 token中获取用户表ID
     *
     * @return token中包含的用户名
     */
    public static String getUserId(String token) {
        if (token == null) return null;
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("upmpuserid").asString();
        } catch (JWTDecodeException e) {
            log.error("error：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 从token中获取失效日期
     * @param token
     * @return
     */
    public static Date getExpireDate(String token) {
        if (token == null) return null;
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getExpiresAt();
        } catch (JWTDecodeException e) {
            log.error("error：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 从token中获取签发日期
     * @param token
     * @return
     */
    public static Date getIssueDate(String token) {
        if (token == null) return null;
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getIssuedAt();
        } catch (JWTDecodeException e) {
            log.error("error：{}", e.getMessage());
            return null;
        }
    }



    /**
     * 生成 token
     *
     * @param userId 用户表Id
     * @param secret   用户的密码
     * @return token
     */
    public static String sign(String userId, String secret) {
        try {
            userId = StringUtils.lowerCase(userId);
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(secret);
            return JWT.create()
                    .withClaim("upmpuserid", userId)
                    .withExpiresAt(date)
                    .withIssuedAt(new Date())
                    .sign(algorithm);
        } catch (Exception e) {
            log.error("error：{}", e);
            return null;
        }
    }

    /**
     * token 加密
     *
     * @param token token
     * @return 加密后的 token
     */
    public static String encryptToken(String token) {
        try {
            return EncryptUtil.byteArr2HexStr(SM4Util.encrypt_CBC_Padding(KEY, IV, token.getBytes()));
        } catch (Exception e) {
            log.info("token加密失败：", e);
            return null;
        }
    }

    /**
     * token 解密
     *
     * @param encryptToken 加密后的 token
     * @return 解密后的 token
     */
    public static String decryptToken(String encryptToken) {
        try {
            return new String(SM4Util.decrypt_CBC_Padding(KEY, IV, EncryptUtil.hexStr2ByteArr(encryptToken)));
        } catch (Exception e) {
            log.warn("token解密失败");
            return null;
        }
    }



    /**
     * 从 token中获取用户名
     *
     * @return token中包含的用户名
     */
    public static String getUpmpUserId(String token) {
        if (token == null) return null;
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("upmpuserid").asString();
        } catch (JWTDecodeException e) {
            log.error("error：{}", e.getMessage());
            return null;
        }
    }
}
